package com.xyd.auth.security.config;

import com.xyd.auth.security.custom.CustomMD5PasswordEncoder;
import com.xyd.auth.security.custom.CustomUserDetailService;
import com.xyd.auth.security.filter.TokenAuthenticationFilter;
import com.xyd.auth.security.filter.TokenLoginFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration // 当前类是一个配置类
@EnableWebSecurity  //@EnableWebSecurity开启Security默认行为
// 开启基于方法的安全认证机制，也就是说在web层的controller启用注解机制的安全确认
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig implements WebSecurityConfigurer {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    protected CustomUserDetailService customUserDetailService;
    @Autowired
    private CustomMD5PasswordEncoder customMD5PasswordEncoder;
    @Autowired
    private AuthenticationConfiguration authenticationConfiguration;


    @Bean
    protected AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 跨站请求伪造
        http
            .csrf(csrf -> csrf.disable())
                // 开启跨域以便前端调用接口
            .cors(Customizer.withDefaults())
                .sessionManagement(session ->session.disable())
        // 指定某些接口不需要通过验证即可访问。登陆接口肯定是不需要认证的
            .authorizeHttpRequests(auth -> auth.requestMatchers(HttpMethod.POST,"/admin/system/index/login").permitAll().anyRequest().authenticated())
//        TokenAuthenticationFilter带有redistemplate的构造器补充
                .addFilterBefore(new TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class)
//        TokenLoginFilter带有redistemplate的构造器补充
                .addFilter(new TokenLoginFilter(authenticationManager(authenticationConfiguration),redisTemplate))
        ;
        return http.build();
    }

    // 放行knife4j 的swggger资源
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer(){
        return webSecurity -> webSecurity.ignoring().requestMatchers("favicon.ico","/swaggerresources/**","/webjars/**","/v3/**","/swaggerui.html/**","/doc.html");
    }

    /**
     * 定义使用自定义的业务层来认证用户
     * @return
     */
    @Bean
    public AuthenticationProvider authenticationProvider(){
        // 持久层认证对象
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        // 设置自定义用户认证业务
        daoAuthenticationProvider.setUserDetailsService(customUserDetailService);
        // 设置自定义加密组件
        daoAuthenticationProvider.setPasswordEncoder(customMD5PasswordEncoder);
        return daoAuthenticationProvider;
    }




    @Override
    public void init(SecurityBuilder builder) throws Exception {

    }

    @Override
    public void configure(SecurityBuilder builder) throws Exception {

    }
}
